var RelativePosition = function(){
    function getLeft(align, rect, rel){
        var iLeft = 0;
        switch (align.toLowerCase()){
            case "left":
                return rect.left - rel.offsetWidth;
            case "clientleft":
                return rect.left;
            case "center":
                return (rect.left + rect.right - rel.offsetWidth) / 2;
            case "clientright":
                return rect.right - rel.offsetWidth;
            case "right":
            default :
                return rect.right;
        };
    };

    function getTop(valign, rect, rel){
        var iTop = 0;
        switch (valign.toLowerCase()){
            case "top":
                return rect.top - rel.offsetHeight;
            case "clienttop":
                return rect.top;
            case "center":
                return (rect.top + rect.bottom - rel.offsetHeight) / 2;
            case "clientbottom":
                return rect.bottom - rel.offsetHeight;
            case "right":
            default:
                return rect.right;
        };
    };
    function getTop(valign, rect, rel){
        var iTop = 0;
        switch (valign.toLowerCase()){
            case "top":
                return rect.top - rel.offsetHeight;
            case "clienttop":
                return rect.top;
            case "center":
                return (rect.top + rect.bottom - rel.offsetHeight) / 2;
            case "clientbottom":
                return rect.bottom - rel.offsetHeight;
            case "bottom":
            default :
                return rect.bottom;
        };
    };

    //定位元素，相对定位元素
    return function(fix, rel, options){
        //默认值
        var opt = $$.extend({
            align: "clientleft", //水平方向定位
            vAlign: "clienttop", //垂直方向定位
            customLeft: 0, //自定义left定位
            customTop: 0, //自定义top定位
            percentLeft: 0, //自定义left百分比定位
            percentTop: 0, //自定义top百分比定位
            adaptive: false, //是否自适应定位
            reset: false //自适应定位时是重新定位
        }, options || {});
        // 定义参数
        var rect = $$D.clientRect(fix),
            iLeft = getLeft(opt.align, rect, rel) + opt.customLeft,
            iTop = getTop(opt.vAlign, rect, rel) + opt.customTop;
        //自定义百分比定位
        if(opt.percentLeft){
            iLeft += .01 * opt.percentLeft + fix.offsetWidth;
        };
        if(opt.percentTop){
            iTop += .01 * opt.percentTop * fix.offsetHeight;
        }
        // 自适应视窗定位
        if(opt.adaptive){
            //修正定位参数
            var doc = fix.ownerDocument,
                maxLeft = doc.clientWidth - rel.offsetWidth,
                maxTop = doc.clientHeight - rel.offsetHeight;
            if(opt.reset){
                // 自动重新定位
                if(iLeft > maxLeft || iLeft < 0){
                    iLeft = getLeft(2 * iLeft > maxLeft ? "left" : "right", rect, rel) + opt.customLeft;
                };
                if(iTop > maxTop || iTop < 0){
                    iTop = getTop(2 * iTop > maxTop ? "top" : "bottom", rect, rel) + opt.customTop;
                };
            }else{
                // 修正到合适位置
                iLeft = Math.max(Math.min(iLeft, maxLeft), 0);
                iTop = Math.max(Math.min(iTop, maxTop), 0);
            };
        };
        // 加上滚动条
        iLeft += $$D.getScrollLeft(fix);
        iTop += $$D.getScrollTop(fix);
        //返回定位参数
        return {Left: iLeft, Top: iTop};
    };
}();
// 容易集合
var FixedMenu = function(containers, optiopns){
    this._timerContainer = null; //容器定时器
    this._timerMenu = null; //菜单定时器
    this._frag = document.createDocumentFragment(); // 碎片对象，保存菜单元素
    this._menus = {}; //菜单对象

    this._containers = []; // 容器集合
    this._setOptions(optiopns);
    var opt = this.options;

    this._custommenu = opt.menu;
    this.css = opt.css;
    this.hover = opt.hover;
    this.active = opt.active;
    this.tag = opt.tag;
    this.html = opt.html;
    this.relContainer = opt.relContainer;
    this.relative = opt.relative;
    this.attribute = opt.attribute;
    this.property = opt.property;
    this.onBeforeshow = opt.onBeforeshow;
    this.delay = parseInt(opt.delay) || 0;

    $$A.forEach($$A.isArray(containers) ? containers : [containers], function(o, i){
        // 自定义容器， id：定位元素 menu：插入菜单元素
        var pos, menu;
        if(o.id){
            pos = o.id;
            menu = o.menu ? o.menu : pos;
        }else{
            pos = menu = o;
        };
        pos = $$(pos);
        menu = $$(menu);
        //容器对象 pos：定位元素 menu：插入菜单元素
        pos && menu && this._iniContainer(i, {"pos": pos, "menu": menu });
    }, this);

    // 初始化程序
    this._iniMenu();
};

FixedMenu.prototype = {
    //设置默认属性
    _setOptions: function(options){
        this.options = { // 默认值
            menu:           [], //自定义菜单集合
            delay:          200, //延迟值(微妙)
            tag:            "div", //默认生成标签
            css:            undefined, //默认样式
            hover:          undefined,  //触发菜单样式
            active:         undefined,  // 显示下级菜单时显示样式
            html:           "",         // 菜单内容
            relContainer:   false,      // 是否相对容器定位(否则相对菜单)
            relative:       {align: "clientleft", vAlign: "bottom"},    // 定位对象
            attribute:      {},         //自定义attribute 属性
            property:       {},         // 自定义property属性
            onBeforeShow:       function(){}    //菜单显示时执行
        };
        $$.extend(this.options, options || {});
    },

    //程序初始化
    _iniMenu: function(){
        this.hide(); //隐藏菜单
        this._buildMenu(); //生成菜单对象
        this._forEachContainer(this._resetContainer); // 重置容器属性
        this._insertMenu(0, 0); //显示菜单
    },

    // 根据自定义菜单对象生成程序菜单对象
    _buildMenu: function(){
        // 清楚旧菜单dom(包括自定义的)
        this._forEachMenu(function(o){
            var elem = o._elem;
            if(elem){
              // 防止dom内存泄露
                $$E.removeEvent(elem, "mouseover", o._event);
                elem.parentNode.removeChild(elem);
                o._elem = o.elem = null;
            };
        });

        //设置菜单默认值
        var options = {
            id:             0, //id
            rank:           0, // 排序
            elem:           "", // 自定义元素
            tag:            this.tag,
            css:            this.css,
            hover:          this.hover,
            active:         this.active,
            html:           this.html,
            relContainer:   !!this.relContainer,
            relative:       this.relative,
            attribute:      this.attribute,
            property:       this.property
        };

        //先定义"0"顶级菜单
        this._menus = {"0": {"_children" : []}};

        //整理自定义菜单并插入到程序菜单对象
        $$A.forEach(this._custommenu, function(o){
            // 生成菜单对象（由于包含对象，要用深度扩展）
            var menu = $$.deepextend($$.deepextend({}, options), o || {});
            // 去掉相同id菜单，同时排除了id为"0"的菜单
            if(!!this._menus[menu.id]){
                return;
            };
            // 重复属性
            menu._children = [];
            menu._index = -1;
            this._menus[menu.id] = menu;
        }, this);

        //建立树形结构
        this._forEachMenu(function(o, id, menus){
            if("0" == id){  //顶级没有父亲菜单
                return;
            };
            var parent = this._menus[o.parent];
            // 父级菜单不存在或者父级是自己的话，当成一级菜单
            if(!parent || parent === o){
                parent = menus[o.parent = "0"];
            };
            // 插入到父级菜单对象的_children 中
            parent._children.push(o)
        });

        //整理菜单对象
        this._forEachMenu(function(o){
            //如果有自定义元素的话，先放到碎片文档中
            !!o.elem && (o.elem = $$(o.elem)) && this._frag.appendChild(o.elem);
            //修正样式，优先使用自定义元素的class
            if(!!o.elem && o.elem.className){
                o.css = o.elem.className;
            }else if(o.css === undefined){
                o.css = "";
            };

            if(o.hover === undefined){
                o.hover = o.css;
            };
            if(o.active === undefined){
                o.active = o.hover;
            };
            // 对菜单对象的_children集合排序(先按rank 再按id排序)
            o._children.sort(function(x, y){
                return x.rank - y.rank || x.id - y.id;
            });
        });
    },

    //插入菜单
    _insertMenu: function(index, parent){
        var container = this._containers[index];
        // 如果是同一个父级菜单 不用重复插入
        if( container._parent === parent){
            return;
        };

        container._parent = parent;
        // 把原有容器内菜单移到碎片对象中
        $$A.forEach(container._menus, function(o){
            o._elem && this._frag.appendChild(o._elem);
        }, this);
        //重置子菜单对象集合
        container._menus = [];
        //把从父级菜单元素的子菜单对象集合获取的元素插入到容器
        $$A.forEach(this._menus[parent]._children, function(menu, i){
            this._checkMenu(menu, index); //检查菜单
            container._menus.push(menu); //加入到容器的子菜单集合，方便调用
            container.menu.appendChild(menu._elem); //菜单元素插入到容器
        }, this);
    },

    //检查菜单
    _checkMenu: function(menu, index){
        //索引保存到菜单对象属性中，方便调用
        menu._index = index;
        // 如果菜单对象没有元素
        if(!menu._elem){
            var elem = menu.elem;
            //如果没有自定义元素的话，创建一个
            if(!elem){
                elem = document.createElement(menu.tag);
                elem.innerHTML = menu.html;
            };
            //设置property
            $$.extend(elem, menu.property);
            // 设置attribute
            var attribute = menu.attribute;
            for(var att in attribute){
                elem.setAttribute(att, attribute[att]);
            };
            //设置样式
            elem.className = menu.css;
            //设置事件
            menu._event = $$F.bindAsEventListener(this._hoverMenu, this, menu);     // 用于消除事件
            $$E.addEvent(elem, "mouseover", menu._event);
            // 保存到菜单对象
            menu._elem = elem;
        };
    },
    // 触发菜单
    _hoverMenu: function(e, menu){
        var elem = menu._elem;
        // 如果是内部元素触发直接返回
        if($$D.contains(elem, e.relatedTarget) || elem === e.relatedTarget){
            return;
        };
        clearTimeout(this._timerMenu);
        // 可能在多个容器间移动，所以全部容器都重新设置样式
        this._forEachContainer(function(o, i){
           if(o.pos.visibility === "hidden"){
               return;
           };
            this._resetCss(o);
            // 设置当前菜单为active样式
            var menu = o._active;
            if(menu){
                menu._elem.className = menu.active;
            };
        });
        //设置当前菜单为触发样式
        if(this._containers[menu._index]._active !== menu){
            elem.className = menu.hover;
        };
        //触发显示菜单
        this._timerMenu = setTimeout($$F.bind(this._showMenu, this, menu), this.delay);
    },
    //显示菜单
    _showMenu: function(menu){
        var index = menu._index, container = this._containers[index], child = !!menu._children.length;
        // 隐藏不需要的容器
        this.forEachContainer(function(o, i){
            i > index && this._hideContainer(o);
        });
        // 重置当前容器_active
        container._active = null;
        // 如果有子级菜单
        if(child){
            // 设置当前容器 _active
            container._active = menu;
            // 显示下一级容器
            index++;
            this._checkContainer(index); //检查容器
            this._insertMenu(index, menu.id); //插入菜单
            this._showContainer(menu); // 显示容器
        };
        //重置当前容器的css
        this._resetCss(container);
        // 设置当前菜单样式
        menu._elem.className = child ? menu.active : menu.hover;
    },
    //初始化容器(索引，容器元素)
    _iniContainer: function(index, container){
        var oContainer = container.pos;
        //重置属性
        this._resetContainer(container);
        //添加事件
        $$E.addEvent(oContainer, "mouseover", $$F.bind(function(){clearTimeout(this._timerContainer);}, this));
        $$E.addEvent(oContainer, "mouseout", $$F.bindAsEventListener(function(e){
            //先判断是否移出到所有容器之外
            var elem = e.relatedTarget,
                isOut = $$A.every(this._containers, function(o){
                    return o.pos === elem || !($$D.contains(o.pos, elem));
                });
                if(isOut){
                    //清除定时器并隐藏
                    clearTimeout(this._timerContainer);
                    clearTimeout(this._timerMenu);
                    this._timerContainer = setTimeout($$F.bind(this.hide, this), this.delay);
                }
        }, this));
        //除了第一个容器外设置浮动样式
        if(index){
            $$D.setStyle(container.pos, {
                position: "absolute", display: "block", margin: 0,
                zIndex: this._containers[index - 1].pos.style.zIndex + 1// 要后面的覆盖前面的
            });
        };
        //ie6 处理 select
        if($$B.ie6){
            var iframe = document.createElement("<iframe style='position:absolute;filter:alpha(opacity=0);display:none;'>");
            document.body.insertBefore(iframe, document.body.childNodes[0]);
            container._iframe = iframe;
        };
        //记录索引，方便使用
        container._index = index;
        // 插入到容器集合
        this._containers[index] = container;
    },
    //检查容器
    _checkContainer: function(index){
        if(index > 0 && !this._containers[index]){
            //如果容器不存在，根据前一个容器复制成新容器，第一个容器必须自定义
            var pre = this._containers[index - 1].pos;
            //用了新的添加事件方式，没有ie的cloneNode的bug
            var container = pre.parentNode.insertBefore(pre.cloneNode(false), pre);
            //清除id，防止冲突
            container.id = "";
            //初始化容器
            this._iniContainer(index, {"pos": container, "menu": container});
        };
    },
    //显示容器
    _showContainer: function(menu){
        var index = menu._index,
            container = this._containers[index + 1].pos,
            elem = menu.relContainer ? this._containers[index].pos : menu._elem,
            pos = RelativePosition(elem, container, menu.relative);
        //执行显示前事件
        this.onBeforeshow(container, menu);
        //定位并显示容器
        $$D.setStyle(container,{
            left: pos.Left + "px", top: pos.Top + "px", visibility: "visible"
        });
        //ie6 处理select
        if($$B.ie6){
            $$D.setStyle(this._containers[index + 1]._iframe, {
                width: container.offsetWidth + "px",
                height: container.offsetWidth + "px",
                left: pos.Left + "px", top: pos.Top + "px",
                display: ""
            });
        };
    },
    //隐藏容器
    _hideContainer: function(container){
        //设置隐藏
        $$D.setStyle(container.pos, {left: "-9999px", top: "-9999px", visibility: "hidden"});
        //重置上一个菜单的触发菜单对象
        this._containers[container._index - 1]._active = null;
        this._containers[container._index - 1]._active = null;
        //ie6处理select
        if($$B.ie6){
            container._iframe.style.display = "none";
        };
    },
    //重置容器对象属性
    _resetContainer: function(container){
        container._active = null; //重置触发菜单
        container._menus = []; //重置子菜单对象集合
        container._parent = -1; //重置父级菜单id
    },
    //隐藏菜单
    hide: function(){
        this._forEachContainer(function(o, i){
            if(i === o){
                //如果是第一个重设样式和_active
                this._resetCss(o);
            }else{
                // 隐藏容器
                this._hideContainer(o);
            }
        });
    },
    //重设容器菜单样式
    _resetCss: function(container){
        $$A.forEach(container._menus, function(o, i){o._elem.className = o.css; }, this);
    },
    //遍历菜单对象集合
    _forEachMenu: function(callback){
        for(var id in this._menus){
            callback.call(this, this._menus[id], id, this._menus);
        };
    },
    //遍历容器对象集合
    _forEachContainer: function(callback){
        $$A.forEach(this._containers, callback, this);
    },
    //添加自定义菜单
    add: function(menu){
        this._custommenu = this._custommenu.concat(menu);
        this._iniMenu();
    },
    //修改自定义菜单
    edit: function(menu){
        $$A.forEach($$A.isArray(menu) ? menu : [menu], function(o){
            //如果对应id的菜单存在
            if(o.id && this._menu[o.id]){
                //从自定义菜单中找出对应菜单，并修改
                $$A.every(this._custommenu, function(m, i){
                    if(m.id === o.id){
                        this._custommenu[i] = $$.deepextend(m, o);
                        return false;
                    };
                    return true;
                }, this);
            };
        }, this);
        this._iniMenu();
    },
    //删除自定义菜单
    del: function(){
        var ids = Array.prototype.slice.call(arguments);
        this._custommenu = $$A.filter(this._custommenu, function(o){
            return $$A.indexOf(ids, o.id) === -1;
        });
        this._iniMenu();
    }
};

